package com.mkyong.rest;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

import com.mkyong.Track;
import com.mkyong.wowData;
import com.projectY.dao.DataDb;
import com.projectY.dao.user;


@Path("/extension")
public class JSONService {
	
	protected static DataDb dataDb= new DataDb();
	protected static HashMap<String,String> megrgedUuids=new HashMap<String,String>(); 
	@GET
	@Path("/get")
	@Produces(MediaType.APPLICATION_JSON)
	public Track getTrackInJSON() {

		Track track = new Track();
		track.setTitle("Enter Sandman");
		track.setSinger("Metallica");

		return track;

	}

	@POST
	@Path("/getLinkUpvotes")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response createTrackInJSON(String track) throws JSONException, SQLException {
//		{"links":["http://www.cs.utexas.edu/users/djimenez/utsa/cs1723/lecture2.html",
//		          "http://dl.acm.org/citation.cfm?id=73040","http://en.wikipedia.org/wiki/Heap_(data_structure)",
//		          "http://en.wikipedia.org/wiki/Heap_(data_structure)"],"user":"singh.ishupreet@gmail.com","site":"twitter"}
		System.out.println(track+" track");
		JSONObject obj=new JSONObject(track);
		JSONArray linksArray= obj.getJSONArray("links");
		ArrayList<String> links=new ArrayList<String>();
		for(int i=0;i<linksArray.length();i++)
		{
			links.add(linksArray.getString(i));
		}
		JSONArray friendsArray=new JSONArray();
		String site=obj.getString("site");
		String user = obj.getString("user");
		ArrayList<String> friends=new ArrayList<String>();
		String uuid=dataDb.getUserId(user,checkType(user));
		if(site.equalsIgnoreCase("selfLike"))
		{
			friends.add(uuid);
		}
		else
		{friendsArray= dataDb.getFriends(uuid);
		for(int i=0;i<friendsArray.length();i++)
		{
			friends.add(friendsArray.getString(i).toLowerCase());
		}
		
		}
		System.out.println(links+" \n "+friends);
		JSONObject res=new JSONObject(new DataDb().readLinksProfile(links,friends));
		res.put("site", site);
		return Response.status(201).entity(res).build();
	}
	@POST
	@Path("/storeFriends")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response storeFriends(String track) throws JSONException, SQLException {
		System.out.println(track+" track");
		JSONObject obj=new JSONObject(track);
		final String user=obj.getString("user");
		final JSONArray friendsArray=new JSONArray(obj.getString("friends"));
		final String friends=(obj.getString("friends"));
		friends.replace('[','(');
		friends.replace(']',']');
		
		Runnable r = new Runnable() {
	         public void run() {
	        	try {
					dataDb.storeFriends(user,friends,friendsArray);
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	         }
	     };

	     new Thread(r).start();
		JSONObject res=new JSONObject();
		res.put("result", "Saving the data in separate thread");
		return Response.status(201).entity(res).build();
		
	}

	@POST
	@Path("/storeUser")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response storeUser(String track) throws JSONException, SQLException {
		boolean mergeFlag=false;
		String oldUuId="";
		System.out.println(track+" track");
		JSONObject obj=new JSONObject(track);
		String uuid=obj.getString("uuid");
		String user=obj.getString("user");
		String type=checkType(user);
		user oldRow=dataDb.checkSavedEntryForUserId(user,type);
		if(megrgedUuids.containsKey(uuid))
		{
			
			boolean mergeConflict=dataDb.checkConflict(megrgedUuids.get(uuid),user,type);
			dataDb.rollBack(uuid);
			if(mergeConflict)
			{
				JSONObject res=new JSONObject();
				res.put("result", "Merge Conflict");
				return Response.status(201).entity(res).build();
			}
			else
			{
				JSONObject res=new JSONObject();
				res.put("result", "Data saved successfully");
				return Response.status(201).entity(res).build();
			}
		
		}
		if(oldRow!=null)
		{
			oldUuId=oldRow.getString("id");
			mergeFlag=!uuid.equals(oldUuId);
			if(megrgedUuids.containsKey(uuid))
			{
				boolean mergeConflict=dataDb.checkConflict(oldUuId,user,type);
				dataDb.rollBack(uuid);
				if(mergeConflict)
				{
					JSONObject res=new JSONObject();
					res.put("result", "Merge Conflict");
					return Response.status(201).entity(res).build();
				}
				else
				{
					JSONObject res=new JSONObject();
					res.put("result", "Data saved successfully");
					return Response.status(201).entity(res).build();
				}
			}
			else
			{
				megrgedUuids.put(uuid,oldUuId);
			}
		}
		
		user newRow=dataDb.checkUsedUuid(uuid);
		if(newRow==null)
		{
			dataDb.storeUuidUser(uuid,user,type);
		}
		else
		{	String storedUserId=newRow.getString(type+"_user_name");
			if(storedUserId==null || storedUserId.equals(user))
			{
				dataDb.storeOldUuidUser(uuid,user,type);
			}
		}
		if(mergeFlag)
		{
			megrgedUuids.put(uuid,oldUuId);
			boolean mergeable=dataDb.mergeUuids(oldRow,oldUuId,uuid);
			if(!mergeable)
			{
				dataDb.rollBack(uuid);
				JSONObject res=new JSONObject();
				res.put("result", "Problem saving data");
				return Response.status(201).entity(res).build();
			}
		}
		JSONObject res=new JSONObject();
		res.put("result", "Data saved successfully");
		return Response.status(201).entity(res).build();
		
	}

	private Response checkTwo(ArrayList<JSONObject> jObjs) throws SQLException, JSONException {
		String storedId=null;
		JSONObject res=new JSONObject();
		ArrayList<String> idsToBeStored=new ArrayList<String>();
		for(JSONObject jObj: jObjs)
		{
			if(jObj.has("user"))
			{
				String userId = jObj.getString("user");
				String newId = dataDb.getUserId(userId,checkType(userId));
				if(storedId!=null && newId!=null && !storedId.equals(newId))
				{
					res.put("result", "Conflicting data");
					return Response.status(201).entity(res).build();
				}
				if(newId==null)
				{
					idsToBeStored.add(userId);
				}
				else
				{
					storedId=newId;
				}
			}
		}
		for(String id: idsToBeStored)
		{
			long newStoredId = dataDb.storeId(id,checkType(id),storedId);
			if(newStoredId>0)
			{
				storedId=String.valueOf(newStoredId);
				res.put("site", "Data stored");;
			}
			else if(newStoredId==-1)
			{
				res.put("result", "Conflicting data");
			}
		}
				
		if(idsToBeStored.size()==0)
		{
			res.put("site", "Data already there");;
		}
			
		return Response.status(201).entity(res).build();
	}

	private Response checkOne(ArrayList<JSONObject> jObjs) throws JSONException, SQLException {
		String id="";
		for(JSONObject jObj: jObjs)
		{
			if(jObj.has("user"))
			{
				id=jObj.getString("user");
				break;
			}
		}
		String type=checkType(id);
		String storedId=dataDb.getUserId(id,type);
		JSONObject res=new JSONObject();
		if(storedId==null)
		{
			long rowsStored=dataDb.storeId(id,type,null);
			if(rowsStored!=0)
			{
				res.put("result", "Data stored");
			}
			else
			{
				res.put("result", "Problem saving data");
			}
		}
		else
		{
			res.put("site", "Data already there");
		}
		return Response.status(201).entity(res).build();
			
	}

	private String checkType(String user) {

		if(user.contains("fb"))
			return "fb";
		else 
			if(user.contains("gmail"))
			return "gm";
		else  
			return "tw";
	
	}

	@POST
	@Path("/getNonFriendLinkUpvotes")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response getNonFriendLinkUpvotes(String track) throws JSONException, SQLException {
//		{"links":["http://www.cs.utexas.edu/users/djimenez/utsa/cs1723/lecture2.html",
//		          "http://dl.acm.org/citation.cfm?id=73040","http://en.wikipedia.org/wiki/Heap_(data_structure)",
//		          "http://en.wikipedia.org/wiki/Heap_(data_structure)"],"friends":["arushi","sumit","vrinda","ishu"],"site":"twitter"}
		System.out.println(track+" track");
		JSONObject obj=new JSONObject(track);
		JSONArray linksArray= obj.getJSONArray("links");
		ArrayList<String> links=new ArrayList<String>();
		for(int i=0;i<linksArray.length();i++)
		{
			links.add(linksArray.getString(i));
		}
		String site=obj.getString("site");
		
		JSONObject res=new JSONObject(new DataDb().getNonFriendLinkData(links));
		res.put("site", site);
		return Response.status(201).entity(res).build();
	}

	
	@POST
	@Path("/upVote")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response upVote(String track) throws JSONException, SQLException {
//		{"link":"http://www.mkyong.com/jdbc/jdbc-sasa-example-insert-a-record","user":"ishu"}
		JSONObject obj=new JSONObject(track);
		System.out.println(track);
		String user=dataDb.getUserId(obj.getString("user"), checkType(obj.getString("user")));
		int res= new DataDb().Vote(obj.getString("link"),user,obj.getInt("vote"),obj.getString("query"),obj.getInt("tty"));
		System.out.println(res);
		JSONObject result = new JSONObject();


		if(res==-1)
		{
			result.put("result","alreadyThere");
		}
		else
		if(res==1)
		{
			result.put("result","success");
		}
		else
		{
			result.put("result","failure");
		}
		return Response.status(201).entity(result).build();
	}
	
	@POST
	@Path("/getWow")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response getWow(String track) throws JSONException, SQLException {
//		{"link":"http://www.mkyong.com/jdbc/jdbc-sasa-example-insert-a-record","user":"ishu","site":"wow","query":"football"}
		System.out.println(track);
		JSONObject obj=new JSONObject(track);
		String user = obj.getString("user");
		String uuid=dataDb.getUserId(user,checkType(user));
		JSONArray friendsArray= dataDb.getFriends(uuid);
		JSONArray linksArray= obj.getJSONArray("links");
		String query = obj.getString("query");
		//System.out.println("AKSHAY1 linksArray:" + linksArray);
		//System.out.println("AKSHAY2 friendsArray:" + friendsArray);
		//System.out.println("AKSHAY3 query:" + obj.getString("query"));
		
		ArrayList<String> links=new ArrayList<String>();
		for(int i=0;i<linksArray.length();i++)
		{
			links.add(linksArray.getString(i));
		}
		String site=obj.getString("site");

		ArrayList<String> friends=new ArrayList<String>();
		for(int i=0;i<friendsArray.length();i++)
		{
			friends.add(friendsArray.getString(i).toLowerCase());
		}
		//System.out.println("AKSHAY4: links+friends arraylist" + links + " \n " + friends);
		
		List<wowData> wd = new ArrayList<wowData>(new DataDb().getWowData(links,friends));
		new wowData();
		for(wowData iterator: wd) {
			System.out.println("AKSHAY7 " + iterator);
		}
		
		ArrayList<String> friends2 = new ArrayList<String>();
		List<wowData> wd2 = new ArrayList<wowData>(new DataDb().getWowData(links, friends2));
		for(wowData iterator: wd2) {
			System.out.println("AKSHAY8 " + iterator);
		}
		
		//for each link
			//step 1
			//call function by sending individual link {(String)linksArray.get(i)} and friends of particular website
		    //db query should get search query and minutes spent on that link
			//return number1
		
			//step 2
			//call function by sending individual link {(String)linksArray.get(i)} to get all results back
		    //db query should get search query and minutes spent on that link
		    //return number2
		
		    //r1 = (n1*2 + n2*1)/30
			//return r1+r2+r3/3
		
		//initialize wow factors in result hashmap to zero
		HashMap<String,Float> linksFriendsMap=new HashMap<String,Float>();
		for(int i=0;i<linksArray.length();i++)
		{
			linksFriendsMap.put((String)linksArray.get(i), (float)0.0);
		}
		
		HashMap<String,Float> linksMap=new HashMap<String,Float>();
		for(int i=0;i<linksArray.length();i++)
		{
			linksMap.put((String)linksArray.get(i), (float)0.0);
		}
		
		HashMap<String,Float> linksFriendsTotalTimeMap=new HashMap<String,Float>();
		for(int i=0;i<linksArray.length();i++)
		{
			linksFriendsTotalTimeMap.put((String)linksArray.get(i), (float)0.0);
		}
		
		HashMap<String,Float> linksTotalTimeMap=new HashMap<String,Float>();
		for(int i=0;i<linksArray.length();i++)
		{
			linksTotalTimeMap.put((String)linksArray.get(i), (float)0.0);
		}
		
		HashMap<String,Integer> res=new HashMap<String,Integer>();
		for(int i=0;i<linksArray.length();i++)
		{
			res.put((String)linksArray.get(i), 0);
		}

		calculateMaps(linksArray, query,  wd, linksFriendsMap, linksFriendsTotalTimeMap);
		calculateMaps(linksArray, query, wd2,        linksMap,        linksTotalTimeMap);
//		for(wowData iterator: wd) {
//			System.out.println("AKSHAY9 " + iterator);
//			//System.out.println("AKSHAY9 " + query);
//			float matchCount = 0;
//			//find number of words
//			String[] words = getWordsInQuery(iterator.getQuery());
//			for(int i =0;i<words.length;i++) {
//				if(query.contains(words[i])) {
//					matchCount++;
//				}
//				//System.out.println(words[i] + query.contains(words[i]));
//			}
//			String[] queryWords = getWordsInQuery(query);
//			//System.out.println("AKSHAY10: matchCount: " + matchCount);
//			float matchFactor = matchCount/(float)queryWords.length;
//			//System.out.println("AKSHAY10: matchfator: " + matchFactor);
//			float rowOutput = matchFactor * iterator.getTime();
//			System.out.println("AKSHAY11: rowOutput: " + rowOutput);
//			
//			if(iterator.getVote() == 1) {
//			//add to result
//				linksFriendsMap.put(iterator.getLink(), linksFriendsMap.get(iterator.getLink()) + rowOutput);
//			} else {
//			//subtract from result	
//				linksFriendsMap.put(iterator.getLink(), linksFriendsMap.get(iterator.getLink()) - rowOutput);
//			}
//			
//			linksFriendsTotalTimeMap.put(iterator.getLink(), linksFriendsTotalTimeMap.get(iterator.getLink()) + iterator.getTime());
//		}
//		
		for(int i=0;i<linksArray.length();i++)
		{
			System.out.println((String)linksArray.get(i) + " : " + linksFriendsMap.get((String)linksArray.get(i)));
		}
		
		for(int i=0;i<linksArray.length();i++)
		{
			System.out.println((String)linksArray.get(i) + " : " + linksFriendsTotalTimeMap.get((String)linksArray.get(i)));
		}

		for(int i=0;i<linksArray.length();i++)
		{
			System.out.println((String)linksArray.get(i) + " : " + linksMap.get((String)linksArray.get(i)));
		}
		
		for(int i=0;i<linksArray.length();i++)
		{
			System.out.println((String)linksArray.get(i) + " : " + linksTotalTimeMap.get((String)linksArray.get(i)));
		}
		
		for(int i=0;i<linksArray.length();i++)
		{
			int output = 0;
			int friendsToAllFactor = 2;
			
			float temp1 = (linksFriendsMap.get((String)linksArray.get(i))/linksFriendsTotalTimeMap.get((String)linksArray.get(i))) * friendsToAllFactor;
			float temp2 = (linksMap.get((String)linksArray.get(i))/linksTotalTimeMap.get((String)linksArray.get(i)));
			
			float temp3 = (temp1 + temp2)/3;
			output = (int)(temp3 * 100);
			res.put((String)linksArray.get(i), output);
		}
		
		
		JSONObject result = new JSONObject(res);
		Iterator it = res.entrySet().iterator();
		System.out.println("##############################################################################################################");
	    while (it.hasNext()) {
	        Map.Entry pairs = (Map.Entry)it.next();
	        System.out.println(pairs.getKey() + " = " + pairs.getValue());
	        it.remove(); // avoids a ConcurrentModificationException
	    }
	    System.out.println("--------------------------------------------------------------------------------------------------------------");
		result.put("site", site);
		return Response.status(201).entity(result).build();
	}
	
	public String[] getWordsInQuery(String query) {
		String[] words = query.split("\\s+");
		return words;
	}
	
	public void calculateMaps(JSONArray linksArray, String query, List<wowData> wd, HashMap<String,Float> linksFriendsMap, HashMap<String,Float> linksFriendsTotalTimeMap) throws JSONException {
		for(wowData iterator: wd) {
			System.out.println("AKSHAY9 " + iterator);
			//System.out.println("AKSHAY9 " + query);
			float matchCount = 0;
			//find number of words
			String[] words = getWordsInQuery(iterator.getQuery());
			for(int i =0;i<words.length;i++) {
				if(query.contains(words[i])) {
					matchCount++;
				}
				//System.out.println(words[i] + query.contains(words[i]));
			}
			String[] queryWords = getWordsInQuery(query);
			//System.out.println("AKSHAY10: matchCount: " + matchCount);
			float matchFactor = matchCount/(float)queryWords.length;
			//System.out.println("AKSHAY10: matchfator: " + matchFactor);
			float rowOutput = matchFactor * iterator.getTime();
			System.out.println("AKSHAY11: rowOutput: " + rowOutput);
			
			if(iterator.getVote() == 1) {
			//add to result
				linksFriendsMap.put(iterator.getLink(), linksFriendsMap.get(iterator.getLink()) + rowOutput);
			} else {
			//subtract from result	
				//linksFriendsMap.put(iterator.getLink(), linksFriendsMap.get(iterator.getLink()) - rowOutput);
			}
			
			linksFriendsTotalTimeMap.put(iterator.getLink(), linksFriendsTotalTimeMap.get(iterator.getLink()) + iterator.getTime());
		}
		
//		for(int i=0;i<linksArray.length();i++)
//		{
//			System.out.println((String)linksArray.get(i) + " : " + linksFriendsMap.get((String)linksArray.get(i)));
//		}
//		
//		for(int i=0;i<linksArray.length();i++)
//		{
//			System.out.println((String)linksArray.get(i) + " : " + linksFriendsTotalTimeMap.get((String)linksArray.get(i)));
//		}
	}
	
	@POST
	@Path("/storeTimeTaken")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response storeTimeTaken(String track) throws JSONException, SQLException {
//		{"link":"http://www.mkyong.com/jdbc/jdbc-sasa-example-insert-a-record","user":"ishu"}
		track.replace("\\", " ");
		JSONObject obj=new JSONObject(track);
		System.out.println(track);
		int res= new DataDb().storeTimTaken(obj.getString("link"),obj.getString("twitter"),obj.getString("facebook"),obj.getString("gapi") ,obj.getInt("tty"));
		System.out.println(res);
		JSONObject result = new JSONObject();


		if(res==-1)
		{
			result.put("result","alreadyThere");
		}
		else
		if(res==1)
		{
			result.put("result","success");
		}
		else
		{
			result.put("result","failure");
		}
		return Response.status(201).entity(result).build();
	}
	@POST
	@Path("/downVote")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response downVote(String track) throws JSONException, SQLException {
//		{"link":"http://www.mkyong.com/jdbc/jdbc-sasa-example-insert-a-record","user":"ishu"}
		JSONObject obj=new JSONObject(track);
		String user=dataDb.getUserId(obj.getString("user"), checkType(obj.getString("user")));
		int res= new DataDb().downVote(obj.getString("link"),user,obj.getInt("vote"),obj.getString("query"));
		System.out.println(res);
		JSONObject result = new JSONObject();


		if(res==-1)
		{
			result.put("result","alreadyThere");
		}
		else
		if(res==1)
		{
			result.put("result","success");
		}
		else
		{
			result.put("result","failure");
		}
		return Response.status(201).entity(result).build();
	}
	@POST
	@Path("/upVotingFriends")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response upVotingFriends(String track) throws JSONException, SQLException {
//		{"link":"http://www.mkyong.com/jdbc/jdbc-sasa-example-insert-a-record","friends":["ishu","arushi"]}
		JSONObject obj=new JSONObject(track);
		JSONArray friendsArray= obj.getJSONArray("friends");
		ArrayList<String> friends=new ArrayList<String>();
		for(int i=0;i<friendsArray.length();i++)
		{
			friends.add(friendsArray.getString(i));
		}
		JSONArray res=new JSONArray(new DataDb().upVotingFriends(obj.getString("link"),friends));
		System.out.println(res);
		return Response.status(201).entity(res).build();
	}
	
	@POST
	@Path("/isVoted")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response isVoted(String track) throws JSONException, SQLException {
//		{"link":"http://www.mkyong.com/jdbc/jdbc-sasa-example-insert-a-record","friends":["ishu","arushi"]}
		JSONObject obj=new JSONObject(track);
		JSONObject res=new JSONObject( );
		
		System.out.println(obj.getString("user")+" "+ obj.getString("twName")+" "+ obj.getString("gapiName")+" ");
		System.out.println(obj.getString("user") +" "+obj.getString("link") );
		DataDb dataDb2 = new DataDb();
		if (dataDb2.checkIfUpVoted(obj.getString("link"),
				dataDb.getUserId(obj.getString("user"),checkType(obj.getString("user"))))
				|| dataDb2.checkIfUpVoted(obj.getString("link"),
						dataDb.getUserId(obj.getString("user"),checkType(obj.getString("twName"))))
				|| dataDb2.checkIfUpVoted(obj.getString("link"),
						dataDb.getUserId(obj.getString("user"),checkType(obj.getString("gapiName"))))) {
			res.put("result", 1 );
		}
		else
		{
			res.put("result",-1 );
		}
		return Response.status(201).entity(res).build();
	}
	@POST
	@Path("/storeQuery")
	@Consumes(MediaType.APPLICATION_JSON)
	public Response storeQuery(String track) throws JSONException, SQLException {
//		{"link":"http://www.mkyong.com/jdbc/jdbc-sasa-example-insert-a-record","user":"ishu"}
		track.replace("\\", " ");
		JSONObject obj=new JSONObject(track);
		System.out.println(track);
		int res= new DataDb().storeQuery(obj.getString("link"),obj.getString("user"));
		System.out.println(res);
		JSONObject result = new JSONObject();


		if(res==-1)
		{
			result.put("result","alreadyThere");
		}
		else
		if(res==1)
		{
			result.put("result","success");
		}
		else
		{
			result.put("result","failure");
		}
		return Response.status(201).entity(result).build();
	}

}